

#include "Utils.h"
#include "Message.h"

using namespace std;

Message::Message() {
}

Message::~Message() {
}

void Message::packMessageInfo(char* buffer, int endianFormat, int messageType, int retransmission) {

	// [message info] 4 bytes
	//		bit 0 - endian format	(0 - big-endian, 1 - little-endian) // always bigendian
	//		bit 1 - message type	(0 - request, 1 - reply)	// always 0
	//		bit 2 - retransmit		(0 - no, 1 - retransmit)
	//		bit 3-31 - currently unused


	char b_info[4] = {0};

	memmove(buffer, b_info, 4);
}

// message packing for method = 1 (open)

void Message::pack(char* buffer, int requestId, int methodId, string name, string password, int currencyType, float balance) {
	// the message will be in the following structure:
	// [message info] 4 bytes
	//		bit 0 - endian format	(0 - big-endian, 1 - little-endian)
	//		bit 1 - message type	(0 - request, 1 - reply)
	//		bit 2 - retransmit		(0 - no, 1 - retransmit)
	// [request id] int	4 bytes
	// [method id] int 4 bytes
	// [name] variable string at least 8 bytes
	// [password] fixed string 4 bytes
	// [type] currency 4 bytes
	// [balance] float 4 bytes


	char* b_name; // for variable-string (name) only
	char b_temp[4] = {0}; // for everything else (4-bytes)

	int name_length = Utils::calcStringLength(name.length());
	b_name = new char[name_length + 4]; // remember to free memory later

	int position = 0;

	// pack message info
	Message::packMessageInfo(buffer, 0, 0, 0);
	position += 4;

	// pack request id
	Utils::intToBytes(requestId, b_temp);
	memmove(buffer + position, b_temp, 4);
	position += 4;

	// pack method id
	Utils::intToBytes(methodId, b_temp);
	memmove(buffer + position, b_temp, 4);
	position += 4;

	// pack name (note: use b_name instead of b_temp)
	Utils::StringToBytes(name, b_name);
	memmove(buffer + position, b_name, name_length + 4);
	position += name_length + 4;

	// pack password
	Utils::fixedStringToBytes(password, b_temp);
	memmove(buffer + position, b_temp, 4);
	position += 4;

	// pack currency type
	Utils::intToBytes(currencyType, b_temp);
	memmove(buffer + position, b_temp, 4);
	position += 4;

	// pack initial balance
	Utils::floatToBytes(balance, b_temp);
	memmove(buffer + position, b_temp, 4);
	position += 4;

	// MUST DO THIS!
	delete b_name;

}

// message packing for method = 2 (close) & method = 5 (check balance)

void Message::pack(char* buffer, int requestId, int methodId, string name, string password, int accountNum) {
	// the message will be in the following structure:
	// [message info] 4 bytes
	//		bit 0 - endian format	(0 - big-endian, 1 - little-endian)
	//		bit 1 - message type	(0 - request, 1 - reply)
	//		bit 2 - retransmit		(0 - no, 1 - retransmit)
	// [request id] int	4 bytes
	// [method id] int 4 bytes
	// [name] variable string at least 8 bytes
	// [password] fixed string 4 bytes
	// [account num] int 4 bytes


	char* b_name; // for variable-string (name) only
	char b_temp[4] = {0}; // for everything else (4-bytes)

	int name_length = Utils::calcStringLength(name.length());
	b_name = new char[name_length + 4]; // remember to free memory later

	int position = 0;

	// pack message info
	Message::packMessageInfo(buffer, 0, 0, 0);
	position += 4;

	// pack request id
	Utils::intToBytes(requestId, b_temp);
	memmove(buffer + position, b_temp, 4);
	position += 4;

	// pack method id
	Utils::intToBytes(methodId, b_temp);
	memmove(buffer + position, b_temp, 4);
	position += 4;

	// pack name (note: use b_name instead of b_temp)
	Utils::StringToBytes(name, b_name);
	memmove(buffer + position, b_name, name_length + 4);
	position += name_length + 4;

	// pack password
	Utils::fixedStringToBytes(password, b_temp);
	memmove(buffer + position, b_temp, 4);
	position += 4;

	// pack accountNum
	Utils::intToBytes(accountNum, b_temp);
	memmove(buffer + position, b_temp, 4);
	position += 4;

	// MUST DO THIS!
	delete b_name;

}

// message packing for method = 3 (deposit/withdraw)

void Message::pack(char* buffer, int requestId, int methodId, string name, string password, int accountNum, int currencyType, float amount) {
	// the message will be in the following structure:
	// [message info] 4 bytes
	//		bit 0 - endian format	(0 - big-endian, 1 - little-endian)
	//		bit 1 - message type	(0 - request, 1 - reply)
	//		bit 2 - retransmit		(0 - no, 1 - retransmit)
	// [request id] int	4 bytes
	// [method id] int 4 bytes
	// [name] variable string at least 8 bytes
	// [password] fixed string 4 bytes
	// [account num] int 4 bytes
	// [type] currency 4 bytes
	// [amount] float 4 bytes


	char* b_name; // for variable-string (name) only
	char b_temp[4] = {0}; // for everything else (4-bytes)

	int name_length = Utils::calcStringLength(name.length());
	b_name = new char[name_length + 4]; // remember to free memory later

	int position = 0;

	// pack message info
	Message::packMessageInfo(buffer, 0, 0, 0);
	position += 4;

	// pack request id
	Utils::intToBytes(requestId, b_temp);
	memmove(buffer + position, b_temp, 4);
	position += 4;

	// pack method id
	Utils::intToBytes(methodId, b_temp);
	memmove(buffer + position, b_temp, 4);
	position += 4;

	// pack name (note: use b_name instead of b_temp)
	Utils::StringToBytes(name, b_name);
	memmove(buffer + position, b_name, name_length + 4);
	position += name_length + 4;

	// pack password
	Utils::fixedStringToBytes(password, b_temp);
	memmove(buffer + position, b_temp, 4);
	position += 4;

	// pack accountNum
	Utils::intToBytes(accountNum, b_temp);
	memmove(buffer + position, b_temp, 4);
	position += 4;

	// pack currency type
	Utils::intToBytes(currencyType, b_temp);
	memmove(buffer + position, b_temp, 4);
	position += 4;

	// pack amount
	Utils::floatToBytes(amount, b_temp);
	memmove(buffer + position, b_temp, 4);
	position += 4;

	// MUST DO THIS!
	delete b_name;

}

// message packing for method = 6 (transfer)

void Message::pack(char* buffer, int requestId, int methodId, string name, string password, int accountNum, int currencyType, float amount, int accountNumToTransfer) {
	// the message will be in the following structure:
	// [message info] 4 bytes
	//		bit 0 - endian format	(0 - big-endian, 1 - little-endian)
	//		bit 1 - message type	(0 - request, 1 - reply)
	//		bit 2 - retransmit		(0 - no, 1 - retransmit)
	// [request id] int	4 bytes
	// [method id] int 4 bytes
	// [name] variable string at least 8 bytes
	// [password] fixed string 4 bytes
	// [account num] int 4 bytes
	// [type] currency 4 bytes
	// [amount] float 4 bytes
        // [account num to transfer] int 4 bytes


	char* b_name; // for variable-string (name) only
	char b_temp[4] = {0}; // for everything else (4-bytes)

	int name_length = Utils::calcStringLength(name.length());
	b_name = new char[name_length + 4]; // remember to free memory later

	int position = 0;

	// pack message info
	Message::packMessageInfo(buffer, 0, 0, 0);
	position += 4;

	// pack request id
	Utils::intToBytes(requestId, b_temp);
	memmove(buffer + position, b_temp, 4);
	position += 4;

	// pack method id
	Utils::intToBytes(methodId, b_temp);
	memmove(buffer + position, b_temp, 4);
	position += 4;

	// pack name (note: use b_name instead of b_temp)
	Utils::StringToBytes(name, b_name);
	memmove(buffer + position, b_name, name_length + 4);
	position += name_length + 4;

	// pack password
	Utils::fixedStringToBytes(password, b_temp);
	memmove(buffer + position, b_temp, 4);
	position += 4;

	// pack accountNum
	Utils::intToBytes(accountNum, b_temp);
	memmove(buffer + position, b_temp, 4);
	position += 4;

	// pack currency type
	Utils::intToBytes(currencyType, b_temp);
	memmove(buffer + position, b_temp, 4);
	position += 4;

	// pack amount
	Utils::floatToBytes(amount, b_temp);
	memmove(buffer + position, b_temp, 4);
	position += 4;

        // pack accountNumToTransfer
	Utils::intToBytes(accountNumToTransfer, b_temp);
	memmove(buffer + position, b_temp, 4);
	position += 4;

	// MUST DO THIS!
	delete b_name;

}

// message packing for method = 7 (monitor updates)

void Message::pack(char* buffer, int requestId, int methodId, int interval) {
	// the message will be in the following structure:
	// [message info] 4 bytes
	//		bit 0 - endian format	(0 - big-endian, 1 - little-endian)
	//		bit 1 - message type	(0 - request, 1 - reply)
	//		bit 2 - retransmit		(0 - no, 1 - retransmit)
	// [request id] int	4 bytes
	// [method id] int 4 bytes
	// [interval] int 4 bytes

	char b_temp[4] = {0}; // for everything else (4-bytes)

	int position = 0;

	// pack message info
	Message::packMessageInfo(buffer, 0, 0, 0);
	position += 4;

	// pack request id
	Utils::intToBytes(requestId, b_temp);
	memmove(buffer + position, b_temp, 4);
	position += 4;

	// pack method id
	Utils::intToBytes(methodId, b_temp);
	memmove(buffer + position, b_temp, 4);
	position += 4;

	// pack interval
	Utils::intToBytes(interval, b_temp);
	memmove(buffer + position, b_temp, 4);

}
